package shayu.ware.service.impl;

import com.alibaba.fastjson.TypeReference;
import io.renren.common.mq.OrderTo;
import io.renren.common.mq.StockDeteailTo;
import io.renren.common.mq.StockLockedTo;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.Query;
import io.renren.common.utils.R;
import lombok.Data;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;
import shayu.ware.dao.WareSkuDao;
import shayu.ware.entity.*;
import shayu.ware.exception.NoStockException;
import shayu.ware.feign.OrderFeign;
import shayu.ware.feign.ProductFeignService;
import shayu.ware.service.WareOrderTaskDetailService;
import shayu.ware.service.WareOrderTaskService;
import shayu.ware.service.WareSkuService;
import shayu.ware.vo.OrderItemVo;
import shayu.ware.vo.OrderVo;
import shayu.ware.vo.SkuHasStockVo;
import shayu.ware.vo.WareSkuLockVo;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    private WareSkuDao wareSkuDao;

    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private WareOrderTaskService wareOrderTaskService;

    @Autowired
    private WareOrderTaskDetailService wareOrderTaskDetailService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private OrderFeign orderFeign;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                new QueryWrapper<WareSkuEntity>()
        );

        return new PageUtils(page);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addStock(Long skuId, Integer skuNum, Long wareId) {

        // 查询一下这个库存的状态
        List<WareSkuEntity> entities = wareSkuDao.selectList(new QueryWrapper<WareSkuEntity>().eq("ware_id", wareId)
        .eq("sku_id",skuId));
        if (entities == null && entities.size() == 0) {
            // 如果没有 就创建新的外购单
            WareSkuEntity wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setSkuId(skuId);
            wareSkuEntity.setStock(skuNum);
            wareSkuEntity.setWareId(wareId);
            wareSkuDao.insert(wareSkuEntity);

            try {
                R info = productFeignService.info(skuId);
                Map<String, Object> data = (Map<String, Object>) info.get("skuInfo");
                if (info.getCode() == 0) {
                    wareSkuEntity.setSkuName((String) data.get("skuName"));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 直接修改
            wareSkuDao.insert(wareSkuEntity);
        } else {
            // 有就直接修改
            wareSkuDao.addStock(skuId, wareId, skuNum);
        }

    }

    @Override
    public List<SkuHasStockVo> getSkusHasStock(List<Long> skuIds) {
        // 收集仓库的sku信息返回
        List<SkuHasStockVo> collect = skuIds.stream().map((skuId) -> {
            SkuHasStockVo skuHasStockVo = new SkuHasStockVo();
            Long count = baseMapper.getSkuStock(skuId);
            skuHasStockVo.setSkuId(skuId);
            skuHasStockVo.setHasStock(count > 0);
            return skuHasStockVo;
        }).collect(Collectors.toList());

        return collect;
    }

    /**
     * 为某个订单锁定库存
     *
     * @param vo
     * @return
     */
    @Override
    @Transactional(rollbackFor = NoStockException.class)
    public Boolean orderLockStock(WareSkuLockVo vo) {

        // 保存工作单详情
        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        wareOrderTaskEntity.setOrderSn(vo.getOrderSn());
        wareOrderTaskEntity.setCreateTime(new Date());
        wareOrderTaskService.save(wareOrderTaskEntity);


        // 1. 找到每个商品在哪个仓库都有库存
        // 1.1 按照下单的收货地址，找到一个就近仓库，锁定库存
        List<OrderItemVo> locks = vo.getLocked();
        List<SkuWareHasStock> collect = locks.stream().map(item -> {
            SkuWareHasStock stock = new SkuWareHasStock();
            Long skuId = item.getSkuId();
            stock.setSkuId(skuId);
            // 查询这个商品在哪里有库存
            List<Long> wareIds = wareSkuDao.listWareIdHasSkuStock(skuId);
            return stock;
        }).collect(Collectors.toList());

        // 2. 锁库存
        for (SkuWareHasStock hasStock : collect) {
            Boolean SkuStocked = false;

            Long skuId = hasStock.getSkuId();
            List<Long> wareIds = hasStock.getWareId();
            if (wareIds == null || wareIds.size() == 0) {
                throw new NoStockException(skuId);
            }
            // 1. 如果每一个商品都锁定成功，将当前商品锁定了几件发送给MQ
            // 2. 锁定失败，前面保存的工作单信息都回滚了，发送出去的消息，即使要解锁库存，由于在数据库查不到指定的id，所有就不用解锁
            for (Long wareId : wareIds) {
                // 成功就返回1，否则就是0
                Long count = wareSkuDao.lockSkuStock(skuId, wareId, hasStock.getNum());
                if (count == 1) {
                    SkuStocked = true;
                    WareOrderTaskDetailEntity taskDetailEntity = new WareOrderTaskDetailEntity();
                    taskDetailEntity.setSkuId(skuId);
                    taskDetailEntity.setSkuName("");
                    taskDetailEntity.setSkuNum(hasStock.getNum());
                    taskDetailEntity.setTaskId(wareOrderTaskEntity.getId());
                    taskDetailEntity.setLockStatus(1);
                    taskDetailEntity.setWareId(wareId);
                    // 告诉MQ锁库存成功
                    StockLockedTo locked = new StockLockedTo();
                    locked.setId(wareOrderTaskEntity.getId());
                    StockDeteailTo stockDeteailTo = new StockDeteailTo();
                    BeanUtils.copyProperties(taskDetailEntity,stockDeteailTo);
                    locked.setDetailTo(stockDeteailTo);
                    rabbitTemplate.convertAndSend("stock-event-exchange",locked);

                    break;
                } else {
                    // 当前仓库锁失败，重新下一个仓库
                }
            }
            if (SkuStocked == false) {
                throw new NoStockException(skuId);
            }
        }
        return true;
    }

    // 解锁库存
    @Override
    public void unlockStock(StockLockedTo to){
        // 库存订单的id
        StockDeteailTo detailTo = to.getDetailTo();
        Long detailid = detailTo.getId();


        /**
         * 解锁
         * 1.查询数据库关于这个订单的锁定库存信息
         *  有：证明库存锁定成功了
         *      解锁：订单状况
         *         1. 有这个订单，必须解锁库存
         *         2. 有这个订单不一定解锁库存
         *              订单状态：已取消，解锁库存呢
         *                        已支付：不能解锁库存
         */

        WareOrderTaskDetailEntity byId = wareOrderTaskDetailService.getById(detailid);
        if(byId!=null){
            // 解锁
            Long id = to.getId();
            WareOrderTaskEntity taskEntity = wareOrderTaskService.getById(id);
            String orderSn = taskEntity.getOrderSn();
            R orderStatus = orderFeign.getOrderStatus(orderSn);
            if(orderStatus.getCode()==0){
                // 订单数据返回成功
                OrderVo data = orderStatus.getData(new TypeReference<OrderVo>() {
                });
                if(data==null||data.getStatus()==4){
                    // 订单不存了
                    // 订单被取消了 才可以解锁库存
                    if(byId.getLockStatus()==1){
                        // 当前库存工作单详情，状态为1 已锁定但是未解锁才可以解锁
                    unLockStock(detailTo.getId(),detailTo.getWareId(),detailTo.getSkuNum(),detailid);
                    }
                }
            }
        }else{
            // 无需解锁
            throw new RuntimeException("远程调用失败");
        }

    }

    /**
     * 解锁库存
     * @param skuId
     * @param wareId
     * @param num
     * @param taskDetailId
     *
     * 2. 订单失败
     *      锁库存失败
     *   只要解锁库存失败的消息，一定给你要告诉服务解锁失败
     */
    private void unLockStock(Long skuId,Long wareId,Integer num,Long taskDetailId){
        // 解锁库存
        wareSkuDao.unlockStock(skuId,wareId,num);
        // 更新库存工作单状态
        WareOrderTaskDetailEntity entity = new WareOrderTaskDetailEntity();
        entity.setId(taskDetailId);
        entity.setLockStatus(2); // 变成已解锁
        wareOrderTaskDetailService.updateById(entity);
    }

    /**
     *    防止订单服务卡顿 导致订单状态消息一直改不了，库存消息优先过期，查订单状态新建状态，什么都不做就走了
     *    导致卡顿的订单，永远不能解锁库存
     */
    @Transactional
    @Override
    public void unlockStock(OrderTo to){
        String orderSn = to.getOrderSn();
        WareOrderTaskEntity item = wareOrderTaskService.getOrderTaskByOrderSn(orderSn);
        Long id = item.getId();
        List<WareOrderTaskDetailEntity> entities = wareOrderTaskDetailService.list(
                new QueryWrapper<WareOrderTaskDetailEntity>().
                        eq("task_id", id).
                        eq("lock_status", 1));
        for (WareOrderTaskDetailEntity entity:entities){
            unLockStock(entity.getSkuId(),entity.getWareId(),entity.getSkuNum(),entity.getId());
        }
    }

    @Data
    class SkuWareHasStock {
        private Long skuId;
        private Integer num;
        private List<Long> wareId;
    }
}